package com.ming.tflitesingleblur.view;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 水纹原理是这样的：
 * 通过写一个自定义控件，继承view
 * 重写onTouchEvent方法，捕获并处理down和move事件
 * 然后根据这些坐标生成波浪，波浪的圆心就是事件的坐标，半径和透明度则通过一次次的重绘改变，半径增大，透明度减小
 * 以此造成波纹的效果
 * 由于down和move事件发生的一般都很快，但是水纹散开却需要一个过程，所以我们把水纹存储在集合中，依据水纹生成的
 * 顺序来进行计算这个散开的过程
 * 
 * 在此应该学会一件事情 ，就是设置一个flag值，利用用户的touch事件来启动循环，利用数据的计算临界值来结束循环
 * 
 * 定义了一个波浪？一切皆对象？！！
 * 
 * 
 * @author Administrator
 *
 */
public class MyRingWave extends View {
	
	private List<Wave> wList;
	/**
	 * 这个flag是用于控制运动的
	 */
	private boolean isRunning=false;
	/**
	 * 两个波浪圆心之间的最小距离
	 */
	private int MIN_DISTANCE=10;

	public MyRingWave(Context context, AttributeSet attrs) {
		super(context, attrs);
		wList=new ArrayList<Wave>();
	}

	public MyRingWave(Context context) {
		super(context);
		wList=new ArrayList<Wave>();
	}

	public MyRingWave(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		wList=new ArrayList<Wave>();
	}

	private Handler handler=new Handler(){
		public void handleMessage(android.os.Message msg) {
			//半径的增量
			int alphas=r.nextInt(7);
			//刷新数据
			flushData(alphas);
			//刷新页面，也就调用onDraw方法
			invalidate();
			
			//循环调用handler
			if(isRunning){
				handler.sendEmptyMessageDelayed(0,20);//延迟50
			}
		};
	};
	
	/**
	 * onDraw是画view的方法
	 */
	protected void onDraw(android.graphics.Canvas canvas) {
		//在此我们要画的是圆
		//从集合中取出所有的圆，开始画
		for (int x = 0; x < wList.size(); x++) {
			Wave wave=wList.get(x);
			//参数分别是圆心的XY坐标，半径，画笔
			canvas.drawCircle(wave.cx, wave.cy, wave.r, wave.p);
		}
	};
	
	@Override
	/**
	 * 重写onTouchEvent()方法，并返回true，让本view可以捕获并消费touch事件
	 */
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		//让用户在down和move事件触发时产生水纹
		//此处利用case穿透，把两个事件集中起来
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
		case MotionEvent.ACTION_MOVE:
			//获得事件的坐标点，以此坐标点为圆心给集合添加圆
			int x=(int) event.getX();
			int y=(int) event.getY();
			
			addPoint(x,y);
			break;
		}
		return true;
	}

	/**
	 * 添加新的波浪中心点
	 * @param x	是中心点的x坐标
	 * @param y	y坐标
	 */
	private void addPoint(int x, int y) {
		if(wList.size()==0){
			addPoint2List(x,y);
			//说明是第一次启动动画,启动Handler
			isRunning=true;
			handler.sendEmptyMessage(0);
		}else{
			//如果不是第一次,获得最后一个波浪
			Wave w=wList.get(wList.size()-1);
			
			//如果移动到的点与上一个波浪的圆心的点大于我们设置的最小距离，我们就在集合中新加一个点
			if(Math.abs(x-w.cx)>MIN_DISTANCE|| Math.abs(y-w.cy)>MIN_DISTANCE){
				addPoint2List(x,y);
			}
		}
	}

	/**
	 * 这个方法是往集合中添加波浪的方法，参数是圆心坐标
	 * @param x
	 * @param y
	 */
	private void addPoint2List(int x, int y) {
		// 根据圆心坐标往集合中添加波浪
		Wave w=new Wave();
		w.cx=x;
		w.cy=y;
		
		Paint p=new Paint();
		//给画笔设置为随机颜色
		//以下的两种随机方法有差别吗？现在前者的颜色会连续出现十个左右的同一种颜色的水纹，然后才换颜色
		//检测结果表示确实不一样，后者的随机数产生的颜色随机性更强一些
//		p.setColor(colors[new Random().nextInt(4)]);
		p.setColor(colors[(int)(Math.random()*5)]);
		//设置画笔风格，不明觉厉
		//把下面的这句注掉，发现圈变成了实心圆
		/*
		 * 也就是说默认的风格是实心的圆  FILL_AND_STROKE  FILL
		 * STROKE则是线条，也就是个圈
		 * 注意：此处的画笔风格的参数是Paint中的一个内部类Sytle,Style是枚举类
		 * 所谓的枚举类，就是一个构造方法私有，但是内部提供有限数量的实例的类
		 * Java中的枚举类的关键字是Enum。如果枚举类中有抽象方法，那么枚举类提供的实例也必须实现这个抽象方法
		 * 于是，我终于解决了这个问题，利用values方法来获得枚举中所有实例的集合，劳资真是机智
		 */
		p.setStyle(styles[(int)(Math.random()*3)]);
//		p.setStyle(Style.FILL_AND_STROKE);
//		p.setStyle(Style.FILL);
		
		w.p=p;
		wList.add(w);
		
	}
	/**
	 * 我在尝试把画笔的风格放在一个集合中,了解枚举是什么东西后，事情就好办了
	 */
	private Style[] styles= Style.values();
	
	/**
	 * 设置一个随机数，并且把它设置成透明度的变化
	 * 因为透明度的变化间接影响水纹的扩散时间，也就是大小 ，所以通过随机数的变化可以把
	 * 水纹变成非均匀分布的
	 */
	private Random r=new Random();
	/**
	 * 刷新数据
	 * 参数是透明度的增量
	 */
	private void flushData(int alphas){
		//遍历集合，
		for (int x = 0; x < wList.size(); x++) {
			Wave w=wList.get(x);
			//如果透明度为0，就从集合中删掉
			int alpha=w.p.getAlpha();
			if(alpha==0){
				wList.remove(x);//此处相当于在遍历集合的时候修改了集合的数据，可能会有bug，看看效果再改
				continue;
			}
			
			//后面的行为说明了透明度是我们把它给一点一点变淡的
			alpha-=9;//透明度每次减5
			if(alpha<9){
				alpha=0;
			}
			
			//降低画笔的透明度
			w.p.setAlpha(alpha);
			//扩大半径，此处半径的增量就是波纹的扩散速度
			w.r+=alphas;
			//设置半径厚度，不明白是什么东西，应该是设置笔画的宽度吧。。
			//已证实，它确实是画笔的画出的线条的宽度。。。在此应该造成了一个结果就是水纹随着半径增大而变粗了
			w.p.setStrokeWidth(w.r/2);
			
			
		}
		
		//如果集合被清空了，就停止刷新动画，也就是把handler停下来
		if(wList.size()==0){
			isRunning=false;
		}
	}
	/**
	 * 圆环的颜色，其实是设置成画笔的颜色
	 */
	private int [] colors = new int[]{Color.BLUE, Color.RED, Color.YELLOW, Color.GREEN, Color.BLACK};
	/**
	 * 定义一个波浪
	 */
	private class Wave{
		//圆心坐标
		int cx;
		int cy;
		//画笔
		Paint p;
		//半径
		int r;
	}
}






